package com.hzeport.bgs22emduty.util;

import cn.hutool.core.bean.BeanUtil;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.google.common.cache.Cache;
import com.google.common.cache.CacheBuilder;
import com.google.common.cache.CacheLoader;
import com.google.common.cache.LoadingCache;
import com.hzeport.bgs22emduty.config.SystemConfig;
import com.hzeport.bgs22emduty.config.login.UserInfoDetailVO;
import com.hzeport.bgs22emduty.dto.BaseDeptInfoTreeDTO;
import com.hzeport.bgs22emduty.entity.*;
import com.hzeport.bgs22emduty.enums.DeleteFlagEnum;
import com.hzeport.bgs22emduty.outbound.*;
import com.hzeport.bgs22emduty.vo.SystemModule.SystemModuleVO;
import com.hzeport.bgs22emduty.auth.adapter.UserService;
import com.hzeport.bgs22emduty.auth.dto.Function;
import com.hzeport.bgs22emduty.auth.dto.Role;
import com.hzeport.bgs22emduty.auth.dto.User;
import com.hzeport.bgs22emduty.common.base.BaseResult;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

@Slf4j
@Component
public class GuavacacheUtils {

    @Autowired
    private  UserService userService;
    @Resource
    private  BaseDeptInfoRepository baseDeptInfoRepository;
    @Resource
    private BasePersonInfoRepository basePersonInfoRepository;
    @Resource
    private BaseGroupInfoRepository baseGroupInfoRepository;
    @Resource
    private ScreenDutyMapsRepository screenDutyMapsRepository;
    @Resource
    private ParamGroupDutyRepository paramGroupDutyRepository;
    @Resource
    private BaseGroupUserRelationRepository baseGroupUserRelationRepository;
    @Resource
    private SystemConfig systemConfig;
    @Resource
    private PersonCurrentCustomRepository personCurrentCustomRepository;
    @Resource
    private ParamDutyRepository paramDutyRepository;


    public String setCustom(String ticket,String customId){
        UserInfoDetailVO userInfoDetailVO=Cache.getUnchecked(ticket);
        if (userInfoDetailVO!=null&&!CollectionUtils.isEmpty(userInfoDetailVO.getCanChooseCustomscode())
        &&userInfoDetailVO.getCanChooseCustomscode().contains(customId)){
            userInfoDetailVO.setCustomscode(customId);
            BaseDeptInfo baseDeptInfo=baseDeptInfoRepository.getById(userInfoDetailVO.getCustomscode());
            userInfoDetailVO.setCustomsName(baseDeptInfo!=null?baseDeptInfo.getDeptName():"");
        }
        if (!systemConfig.getZsCustomId().equals(customId)){
            userInfoDetailVO.setRole(userInfoDetailVO.getRole().stream().filter(i->!"ZGGLY".equals(i)).collect(Collectors.toList()));
        }else {
            List<String> roles=userInfoDetailVO.getRole();
            if (roles!=null&&!roles.contains("ZGGLY")){
                roles.add("ZGGLY");
            }
            userInfoDetailVO.setRole(roles);
        }
        PersonCurrentCustom personCurrentCustom=personCurrentCustomRepository.getOne(new LambdaQueryWrapper<PersonCurrentCustom>()
                .eq(PersonCurrentCustom::getUserNo,userInfoDetailVO.getUserId()),false);
        if (personCurrentCustom!=null){
            personCurrentCustom.setCurrentCustom(customId);
            personCurrentCustom.setUserNo(userInfoDetailVO.getUserId());
            personCurrentCustom.setUserInfoJson(JSONObject.toJSONString(userInfoDetailVO));
            personCurrentCustom.setDelFlag(DeleteFlagEnum.NOT_DELETE.getValue());
            personCurrentCustomRepository.updateById(personCurrentCustom);
        }else {
            personCurrentCustom=new PersonCurrentCustom();
            personCurrentCustom.setCurrentCustom(customId);
            personCurrentCustom.setUserNo(userInfoDetailVO.getUserId());
            personCurrentCustom.setUserInfoJson(JSONObject.toJSONString(userInfoDetailVO));
            personCurrentCustom.setDelFlag(DeleteFlagEnum.NOT_DELETE.getValue());
            personCurrentCustomRepository.save(personCurrentCustom);
        }
        Cache.put(ticket,userInfoDetailVO);

        return "设置成功";
    }

    private  LoadingCache<String, UserInfoDetailVO> Cache = CacheBuilder.newBuilder()
            .expireAfterAccess(15, TimeUnit.MINUTES).build(new CacheLoader<String, UserInfoDetailVO>() {
                @Override
                public UserInfoDetailVO load(String ticket) throws Exception {
                    log.info("in");
                    UserInfoDetailVO userInfoDetailVO = new UserInfoDetailVO();
                    try {
                        if (ticket!=null){
                            User user=userService.getUsers(ticket);
                            log.info("user"+user);
                            userInfoDetailVO.setName(user.getFullPath());
                            userInfoDetailVO.setUserName(user.getName());
                            userInfoDetailVO.setUserId(user.getHrcode());
                            userInfoDetailVO.setPersonId(user.getHrcode());
                            List<Function> functions = userService.getFunctions(ticket);
                            List<String> functionStrings=functions.stream().map(Function::getCode_name)
                                    .collect(Collectors.toUnmodifiableList());
                            List<Role> roles= userService.getRoles(ticket);
                            userInfoDetailVO.setRole(roles.stream().map(Role::getCode_name).collect(Collectors.toList()));
                            List<String> customIds=new ArrayList<>();
                            for (String functionString:functionStrings){
                                log.info("0|"+functionString);
                                if (functionString.contains("DATA_CUS_")) {
                                    log.info("1|"+functionString);
                                    String cusString = functionString.replace("DATA_CUS_", "").replaceAll("_", "-").toLowerCase();
                                    customIds.add(cusString);
                                }
                                if (functionString.contains("SCHEDULE_CJ_MGR")) {
                                    List<String> roleStrings=userInfoDetailVO.getRole();
                                    roleStrings.add("SCHEDULE_CJ_MGR");
                                    userInfoDetailVO.setRole(roleStrings);
                                    List<BasePersonInfo> basePersonInfo=basePersonInfoRepository.list(new LambdaQueryWrapper<BasePersonInfo>()
                                            .eq(BasePersonInfo::getUserno,userInfoDetailVO.getPersonId()));
                                    BasePersonInfo tempBasePerson=basePersonInfo.stream().filter(i->"0".equals(i.getSideLine()))
                                            .findAny().orElse(null);
                                    if (tempBasePerson==null){
                                        tempBasePerson=basePersonInfo.get(0);
                                    }
                                    log.info("de[ts"+tempBasePerson);
                                    List<BaseDeptInfo> baseDeptInfos=baseDeptInfoRepository.list();
                                    if (!CollectionUtils.isEmpty(basePersonInfo)){
                                        BaseDeptInfo parent=baseDeptInfoRepository.getById(tempBasePerson.getDeptId());
                                        if (parent!=null){
                                            BaseDeptInfo father = getParent(parent, baseDeptInfos);
                                            if (father!=null){
                                                userInfoDetailVO.setDeptId(father.getId());
                                            }
                                        }
                                    }
                                }
                            }
                            log.info("最终可选关区列表"+customIds);
                            userInfoDetailVO.setCanChooseCustomscode(customIds);
                            if (!CollectionUtils.isEmpty(customIds)){
                                userInfoDetailVO.setCustomscode(customIds.get(0));
                                BaseDeptInfo baseDeptInfo=baseDeptInfoRepository.getById(userInfoDetailVO.getCustomscode());
                                userInfoDetailVO.setCustomsName(baseDeptInfo!=null?baseDeptInfo.getDeptName():"");
                            }

                        }else{
                            throw new Exception("获取用户信息异常");
                        }
                    }catch (Exception e) {
                        log.error("获取用户信息异常"+e);
                    }
                    return userInfoDetailVO;
                }
            });

    public  UserInfoDetailVO getUserInfoGuava(String ticket){
        UserInfoDetailVO userInfoDetailVO=Cache.getUnchecked(ticket);
        return userInfoDetailVO;
    }

    private  BaseDeptInfo  getParent(BaseDeptInfo baseDeptInfo, List<BaseDeptInfo> baseDeptInfoslist) {
        if (systemConfig.getZsCustomName().equals(baseDeptInfo.getDeptName())){
            return null;
        }
        Map<String,BaseDeptInfo> baseDeptInfoMap=baseDeptInfoslist.stream().filter(i->i.getParentid()!=null).collect(Collectors.toMap(i->i.getId(), i->i));
        BaseDeptInfo father=baseDeptInfoMap.get(baseDeptInfo.getParentid());
        if (father==null){
            return null;
        }
        if (systemConfig.getZsCustomName().equals(father.getDeptName())){
            return baseDeptInfo;
        }
        return getParent(father,baseDeptInfoslist);
    }




    private  LoadingCache<String, List<BaseDeptInfo>> deptCache = CacheBuilder.newBuilder()
            .expireAfterAccess(360, TimeUnit.MINUTES).build(new CacheLoader<String, List<BaseDeptInfo>>() {
                @Override
                public List<BaseDeptInfo> load(String ticket) throws Exception {
                    return baseDeptInfoRepository.list();
                }
            });

    private  LoadingCache<String, List<BasePersonInfo>> personCache = CacheBuilder.newBuilder()
            .expireAfterAccess(360, TimeUnit.MINUTES).build(new CacheLoader<String, List<BasePersonInfo>>() {
                @Override
                public List<BasePersonInfo> load(String ticket) throws Exception {
                    return basePersonInfoRepository.list();
                }
            });
    private  LoadingCache<String, List<BaseGroupInfo>> groupCache = CacheBuilder.newBuilder()
            .expireAfterAccess(360, TimeUnit.MINUTES).build(new CacheLoader<String, List<BaseGroupInfo>>() {
                @Override
                public List<BaseGroupInfo> load(String ticket) throws Exception {
                    return baseGroupInfoRepository.list();
                }
            });


    private  LoadingCache<String, List<BasePersonInfo>> personIncustomCache = CacheBuilder.newBuilder()
            .expireAfterAccess(360, TimeUnit.MINUTES).build(new CacheLoader<String, List<BasePersonInfo>>() {
                @Override
                public List<BasePersonInfo> load(String customId) throws Exception {
                    return basePersonInfoRepository.list(new LambdaQueryWrapper<BasePersonInfo>().eq(BasePersonInfo::getCustomId,customId));
                }
            });

    public   List<BasePersonInfo> getPersons(){
        return personCache.getUnchecked("ticket");
    }

    public   List<BasePersonInfo> getPersonsInCustom(String customId){
        return personIncustomCache.getUnchecked(customId);
    }


    public   List<BaseDeptInfo> getDepts(){
        return deptCache.getUnchecked("ticket");
    }


    private  LoadingCache<String, List<ScreenDutyMaps>> customCache = CacheBuilder.newBuilder()
            .expireAfterAccess(360, TimeUnit.MINUTES).build(new CacheLoader<String, List<ScreenDutyMaps>>() {
                @Override
                public List<ScreenDutyMaps> load(String ticket) throws Exception {
                    return screenDutyMapsRepository.list();
                }
            });
    private  LoadingCache<String, List<ParamGroupDuty>> paramGroupCache = CacheBuilder.newBuilder()
            .expireAfterAccess(360, TimeUnit.MINUTES).build(new CacheLoader<String, List<ParamGroupDuty>>() {
                @Override
                public List<ParamGroupDuty> load(String ticket) throws Exception {
                    return paramGroupDutyRepository.list();
                }
            });
    private  LoadingCache<String, List<BaseGroupUserRelation>> userParamRelationCache = CacheBuilder.newBuilder()
            .expireAfterAccess(360, TimeUnit.MINUTES).build(new CacheLoader<String, List<BaseGroupUserRelation>>() {
                @Override
                public List<BaseGroupUserRelation> load(String ticket) throws Exception {
                    return baseGroupUserRelationRepository.list();
                }
            });

    private  LoadingCache<String, ParamDuty> paramDutyLoadingCache = CacheBuilder.newBuilder()
            .expireAfterAccess(360, TimeUnit.MINUTES).build(new CacheLoader<String, ParamDuty>() {
                @Override
                public ParamDuty load(String id) throws Exception {
                    ParamDuty paramDuty= paramDutyRepository.getByIdIfDel(id);
                    if (paramDuty==null){
                        paramDuty=new ParamDuty();
                    }
                    return paramDuty;
                }
            });

    public   List<ScreenDutyMaps> getCustoms(){
        return customCache.getUnchecked("ticket");
    }

    public List<BaseGroupInfo> getGroups() {
        return groupCache.getUnchecked("ticket");
    }

    public List<ParamGroupDuty> getParamGroup() {
        return paramGroupCache.getUnchecked("ticket");
    }

    public void claerParamGroup() {
         paramGroupCache.invalidateAll();
    }

    public List<BaseGroupUserRelation> getUserGroupRelation() {
        return userParamRelationCache.getUnchecked("ticket");
    }

    public ParamDuty getParamDuty(String id) {
        if (StringUtils.isEmpty(id)){
            return null;
        }
        return paramDutyLoadingCache.getUnchecked(id);
    }

    private Cache<String, List<BasePersonInfo>> getBasePersonInfosInThisDeptCache = CacheBuilder.newBuilder()
            .expireAfterAccess(360, TimeUnit.MINUTES).build();

    public List<BasePersonInfo> getBasePersonInfosInThisDept(String md5, List<BasePersonInfo> persons, BaseDeptInfo baseDeptInfo, List<BaseDeptInfo> allDepts) {
        List<BaseDeptInfo> childern=new ArrayList<>();
        List<BasePersonInfo> basePersonInfos=getBasePersonInfosInThisDeptCache.getIfPresent(md5);
        if (basePersonInfos==null){
            childern.add(baseDeptInfo);
            getChild(baseDeptInfo, childern, allDepts);
            basePersonInfos= persons.stream().filter(i->childern.stream().map(BaseDeptInfo::getId).collect(Collectors.toList())
                    .contains(i.getDeptId())).collect(Collectors.toList());
            getBasePersonInfosInThisDeptCache.put(md5,basePersonInfos);
        }
        return basePersonInfos;
    }

    public void getChild(BaseDeptInfo baseDeptInfo, List<BaseDeptInfo> childrens, List<BaseDeptInfo> deptInfos) {
        List<BaseDeptInfo> myChildren = deptInfos.stream().filter(i -> i.getParentid() != null && i.getParentid().equals(baseDeptInfo.getId())).collect(Collectors.toList());
        if (!CollectionUtils.isEmpty(myChildren)) {
            childrens.addAll(myChildren);
            for (BaseDeptInfo child : myChildren) {
                getChild(child, childrens, deptInfos);
            }
        } else {
            return;
        }
    }


    private  LoadingCache<String, BaseResult> deptTreeCache = CacheBuilder.newBuilder()
            .expireAfterAccess(360, TimeUnit.MINUTES).build(new CacheLoader<String, BaseResult>() {
                            @Override public BaseResult load(String customId) throws Exception {
                                List<BaseDeptInfoTreeDTO> allParam = getDepts().stream().map(item -> {
                                    BaseDeptInfoTreeDTO paramTreeVo = new BaseDeptInfoTreeDTO();
                                    BeanUtil.copyProperties(item,paramTreeVo);
                                    return paramTreeVo;
                                } ).collect( Collectors.toList() );


                                BaseDeptInfo baseDeptInfo =
                                        baseDeptInfoRepository.getById(customId);
                                BaseDeptInfoTreeDTO paramTreeVo = new BaseDeptInfoTreeDTO();
                                BeanUtil.copyProperties(baseDeptInfo,paramTreeVo);
                                //一级节点
                                List< BaseDeptInfoTreeDTO > rootNodes = Arrays.asList(paramTreeVo);
                                //子节点集合
                                List< BaseDeptInfoTreeDTO > children = new ArrayList<>();
                                for ( BaseDeptInfoTreeDTO rootNode : rootNodes ) {
                                    getTree( rootNode , allParam , rootNodes );
                                }
                                return BaseResult.ok( rootNodes );
                            }
            });

    public BaseResult deptTree(String customId) {
        return deptTreeCache.getUnchecked(customId);

    }

    private BaseDeptInfoTreeDTO getTree(BaseDeptInfoTreeDTO rootNode, List<BaseDeptInfoTreeDTO> allParam, List<BaseDeptInfoTreeDTO> rootNodes) {
        List<BaseDeptInfoTreeDTO> children=allParam.stream().filter(i->rootNode.getId().equals(i.getParentid())).collect(Collectors.toList());
        rootNode.setChildren(children);
        if(!CollectionUtils.isEmpty(children)){
            for (BaseDeptInfoTreeDTO child:children){
                child.setChildren( getTreeNode( child , allParam , children ) );
            }
        }
        return rootNode;
    }

    private List<BaseDeptInfoTreeDTO> getTreeNode(BaseDeptInfoTreeDTO rootNode, List<BaseDeptInfoTreeDTO> allParam, List<BaseDeptInfoTreeDTO> rootNodes) {
        List<BaseDeptInfoTreeDTO> children=allParam.stream().filter(i->rootNode.getId().equals(i.getParentid())).collect(Collectors.toList());
        if(!CollectionUtils.isEmpty(children)){
            for (BaseDeptInfoTreeDTO child:children){
                child.setChildren( getTreeNode( child , allParam , children ) );
            }
        }else {
            children=null;
        }
        rootNode.setChildren(children);
        return children;
    }
}
